var path = require('path');
var waterfall = require("async/waterfall");
var parallel = require("async/parallel");
var log4js = require(path.resolve(__dirname, '../config/logger'));
var logger = log4js.getLogger('status');
var DbCommon = require('./db');
var request = require('request-promise');
var axios = require("axios");
var paramHandler = require('./parameter');
var qs = require('qs');
var util = require('./util');
var _ = require('lodash');
const Opreators = require('./operator');
const Observer = require('./observe');
const Treechart = require('./treeChart');
var node_echarts = require('node-echarts');
axios.defaults.timeout = 30000;
class Atom {
  constructor(id) {
    this.id = id;
    this.name = '';
    this.parameters = [];
    this.urls = '';
    this.fixed_req_params = '';
    this.auto_req_params = '';
    this.out_params = {};
    this.type = 1;
    this.kind = 1;
    this.categoryId = null;
    this.status = 1;
    this.gridContent = '';
    this.key_params = '';
    this.subAtoms = [];
    this.data = null;
    this.force = false;
  }

  init() {
    var that = this;
    return new Promise(function (resolve, reject) {
      let wheres = [{
        type: 1,
        key: 'id',
        value: that.id
      }]
      let sqlOptions = {
        wheres: wheres,
        table: 'atom'
      }
      DbCommon.getDataById(sqlOptions).then(function (data) {
        if (data.length > 0) {
          that.name = data[0].name;
          that.urls = data[0].urls;
          that.fixed_req_params = data[0].fixed_req_params;
          that.auto_req_params = data[0].auto_req_params;
          that.status = data[0].status;
          that.categoryId = data[0].category_id;
          that.type = data[0].type;
          that.kind = data[0].kind;
          let urls = that.urls.split(",");
          let fixed_req_params = that.fixed_req_params.split("&&");
          let auto_req_params = that.auto_req_params.split("&&");
          for (let index = 0; index < urls.length; index++) {
//          const element = urls[index];
            let element = 'http://query.wedengta.com/query';
            that.subAtoms.push({
              urls: element,
              fixed_req_params: JSON.parse(fixed_req_params[index]),
              auto_req_params: JSON.parse(auto_req_params[index])
            });
          }
          resolve();
        } else {
          reject(new Error('no data find'));
        }
      }).catch(function (error) {
        reject(error);
      });
    })
  }
  // 传入变动参数
  setAutoParams(autoParams) {
    this.out_params = autoParams || {};
  }
  setForce(force) {
    this.force = force;
  }
  getParameters() {
    var that = this;
    return new Promise(function (resolve, reject) {
      let wheres = [{
        type: 1,
        key: 'atom_id',
        value: that.id
      }]
      let sqlOptions = {
        wheres: wheres,
        table: 'atom_parameter'
      }
      DbCommon.getDataById(sqlOptions).then(function (data) {
        if (data.length > 0) {
          that.parameters = data;
      		that.parameters.forEach(item => {
            if (item.is_key) {
              that.key_params = item.name;
            }
          })
      		resolve();
        } else {
          reject(new Error('no data find'));
        }
      }).catch(function (error) {
        reject(error);
      });
    })
  }
  checkData(data) {
    var that = this;
    var b = false;
    if (that.force) {
      b = true;
    } else {
      if (data instanceof Array && data.length > 0) {
        b = true
      } else if (data instanceof Object) {
        let keys = Object.keys(data);
        if (keys.length > 0) {
          b = true;
        }
      }
    }

    return b;
  }
  fetchData() {
    var that = this;
    console.log("fetchData that",that);
    return new Promise(function (resolve, reject) {
      if (that.subAtoms.length > 0) {
        that._params = '';
        var promiseArrs = [];
        if (that.kind == 1 || that.subAtoms.length < 2) {
          console.log("kind=1 || that.subAtoms.length < 2",that.kind,that.subAtoms.length);
          that.subAtoms.forEach(atom => {
            var params = paramHandler.merge(atom.fixed_req_params, atom.auto_req_params, that.out_params);
//          { call: 'kudu', func: 'dw_performance_report.app_report_daily_details'}, { "conds": [ [{"k": "trade_day","op": "=","v": "2019-03-25"}],[] ]}, {"trade_day": "2019-03-25", "dt_code": "000551", "sec_name": "创元科技"}
            that._params += JSON.stringify(params) + ';;';
            promiseArrs.push(axios({
              method: "POST",
              url: atom.urls,
              data: params
            }));
            logger.info('atom参数: ' + that.id + ' urls:' + atom.urls + ' data:' + JSON.stringify(params));
//          data:{"call":"kudu","func":"dw_performance_report.app_report_daily_details","conds":[[{"k":"trade_day","op":"=","v":"2019-03-25"}],[]]}
          })
          axios.all(promiseArrs)
            .then(axios.spread(function () {
              let rets = Array.prototype.slice.call(arguments);
              let datas = [];
              for (let i = 0; i < rets.length; i++) {
                let ret = rets[i];
                logger.info('atom: ' + that.id +',' +'接口返回数据JSON.stringify(ret.data):'+ JSON.stringify(ret.data));
                let b = that.checkData(ret.data.data);
                if (!b || ret.data.code != 0) {
                  logger.info('atom:' + that.id + ',' + 'atomName:' + that.name + ',' + 'url:' + that.urls + ',' + 'params:' + that._params +',' +'获取数据失败。');
                  reject(new Error('原子' + that.id  + ': 获取数据失败 '))
                  break;
                }
                if (ret.data.code == 0) {
                  datas.push(ret.data.data)
                }              
              }
           
              that.data = util.mergeArrays(
                that.parameters,
                datas,
                that.key_params
              )
              logger.info('atom数据: ' + that.id  + ' result data:' + JSON.stringify(that.data));
              that.generateGrid(that.type, that.data, false);
              resolve();
            })).catch(function (error) {
              logger.info('atom数据获取失败: ' + that.id + ' error:' + error.message);
              reject(error)
            })
        } else if (that.kind == 2) {
          console.log("that.kind == 2")
          var subAtoms = that.subAtoms;
          var tasks = [
            function (callback) {
              var url = subAtoms[0].urls;
              var params = paramHandler.merge(subAtoms[0].fixed_req_params, subAtoms[0].auto_req_params, that.out_params);
              axios({
                method: "POST",
                url: url,
                data: params
              }).then(function (res) {
                logger.info('atom: ' + that.id +',' +'接口返回数据JSON.stringify(res.data):'+ JSON.stringify(res.data));
                let b = that.checkData(res.data.data);
                if (!b || res.data.code != 0) {
                  logger.info('atom:' + that.id + ',' + 'atomName:' + that.name + ',' + 'url:' + that.urls + ',' + 'params:' + JSON.stringify(params) +',' +'获取数据失败。');
                  throw new Error('atom: ' + that.id + ' data error')
                }
                if (res.data.code == 0) {
                  var data = res.data.data;
                  if (data instanceof Array) {
                    // 取第二个原子
                    if (subAtoms[1]) {
                      var atom = subAtoms[1];
                      var promiseList = [];
                      var paramArr = [];
                      data.forEach((element, index) => {
                        let p = paramHandler.merge(
                          atom.fixed_req_params,
                          atom.auto_req_params,
                          element
                        );
                        that._params += JSON.stringify(p) + ';;';
                        let options = {
                          method: "POST",
                          url: atom.urls,
                          data: p
                        }
                        promiseList.push(axios(_.cloneDeep(options)))
                      });
                      callback(null, promiseList)
                    }
                  } else {
                    if (subAtoms[1]) {
                      var atom = subAtoms[1];
                      var promiseList = [];
                      var params = paramHandler.merge(
                        atom.fixed_req_params,
                        atom.auto_req_params,
                        data
                      )
                      that._params += JSON.stringify(params);
                      promiseList.push(
                        axios({
                          method: "POST",
                          url: atom.urls,
                          data: params
                        })
                      );
                      callback(null, promiseList)
                    }
                  }
                }
              }).catch(function (err) {
                callback(err)
              })
            },
            function (arr, callback) {
              axios
                .all(arr)
                .then(
                  axios.spread(function () {
                    let rets = Array.prototype.slice.call(arguments);
                    var totalData = [];
                    for (let index = 0; index < rets.length; index++) {
                      let d = rets[index];
                      logger.info('atom: ' + that.id + ',' +'接口返回数据JSON.stringify(d.data):'+ JSON.stringify(d.data));
                      let b = that.checkData(d.data.data);
                      if (!b || d.data.code != 0) {
                        logger.info('atom:' + that.id + ',' + 'atomName:' + that.name + ',' + 'url:' + that.urls + ',' + 'params:' + that._params +',' +'获取数据失败。');
                        throw new Error('atom: ' + that.id + ' data error');
                        break;
                      }
                      if (d.data.code == 0) {
                        totalData.push(d.data.data);
                      }
                    }
                    callback(null, totalData)
                  })
                )
                .catch(err => {
                  callback(err)
                });

            }
          ];
          waterfall(tasks, function (err, result) {
            if (err) {
              logger.info('atom: ' + that.id + ' error:' + err.message);
              reject(err)
            } else {
              that.data = result;
              that.generateGrid(that.type, that.data, false);
              resolve();
            }
          })
        }

      }
    })
  }
  generateGrid(type, data, isReturn) {
    //图表生成表格
    let str = '';
    if (type == 2 && this.kind == 1) {
    	logger.info(' data:' + JSON.stringify(data), "合并同类表格数据");
  		let intable_params = this.parameters.filter(item => {
        return item.is_intable;
     	});
      let is_intable_params = intable_params.sort((a, b) => {
        return a.t_index - b.t_index;
      });
    	let className = `table_column${is_intable_params.length}`
      str = `<div class="xg_table_wrapper"><table class="${className}"><thead><tr>`;
      let mustMerge = false;
      is_intable_params.forEach(element => {
        str += `<th>${element.alias_name}</th>`;
        if(element.is_merge){
        	mustMerge = true;
        }
      });
      str += `</tr></thead>`;
      if (data instanceof Array) {
        str += `<tbody>`;
        if(mustMerge){
					data.forEach(item => {
	        	if(str.indexOf(item.sec_name) < 0){
							let same_data = data.filter(val => {
				        return val.sec_code == item.sec_code;
				     	});
				     	if(item.deal_day){
					     	same_data.sort(function(a, b){
			     		    var value1 = a['deal_day'];
							    var value2 = b['deal_day'];
									return value1 < value2 ? 1 : -1;
								});
				     	};
				     	if(same_data.length > 1){
					     	same_data.forEach((tar, num) =>{
					     		str += `<tr>`;
					     		if(num == 0){
					          is_intable_params.forEach((element, index) => {
					            let value = tar[element.name];
					        		if (element.operator) {
					              value = Opreators[element.operator]([tar], element.name)
					           	};
					            if(element.is_merge){
						            str += `<td rowspan="${same_data.length}">${value}</td>`;
					            } else {
						            str += `<td>${value}</td>`;
					            }
					          });
					     		} else {
					          is_intable_params.forEach((element, index) => {
					            let value = tar[element.name];
					        		if (element.operator) {
					              value = Opreators[element.operator]([tar], element.name)
					           	};
					            if(!element.is_merge){
					            	str += `<td>${value}</td>`;
					            }
					          });
					     		}
			          	str += `</tr>`;
					     	})
				     	} else {
			          str += `<tr>`;
			          is_intable_params.forEach(element => {
			            let value = item[element.name];
			            if (element.operator) {
			              value = Opreators[element.operator]([item], element.name)
			            }
			            str += `<td>${value}</td>`;
			          });
			          str += `</tr>`;
				     	}
	        	}
	        })
        } else {
	        data.forEach(item => {
	          str += `<tr>`;
	          is_intable_params.forEach(element => {
	            let value = item[element.name];
	            if (element.operator) {
	              value = Opreators[element.operator]([item], element.name)
	            }
	            str += `<td>${value}</td>`;
	          });
	          str += `</tr>`;
	        })
        };
        str += `</tbody></table></div>`;
      };
      if (data instanceof Array && data.length == 0) {
        str = `<div></div>`;
      }
    } else if(type == 2 && this.kind == 2){
    	logger.info(' data:' + JSON.stringify(data), "合并同类表格数据");  //[[{}, {}, {}], [{}, {}, {}]]
  		let intable_params = this.parameters.filter(item => {
        return item.is_intable;
     	});
      let is_intable_params = intable_params.sort((a, b) => {
        return a.t_index - b.t_index;
      });
    	let className = `table_column${is_intable_params.length}`
    	if(data instanceof Array && data.length > 1){
    		data.forEach(dataItem =>{
	      	str += `<div class="xg_table_wrapper"><table class="${className}"><thead><tr>`;
		      let mustMerge = false;
		      is_intable_params.forEach(element => {
		        str += `<th>${element.alias_name}</th>`;
		        if(element.is_merge){
		        	mustMerge = true;
		        }
		      });
		      str += `</tr></thead>`;
		      if (dataItem instanceof Array) {
		        str += `<tbody>`;
		        if(mustMerge){
							dataItem.forEach(item => {
			        	if(str.indexOf(item.sec_name) < 0){
									let same_data = dataItem.filter(val => {
						        return val.sec_code == item.sec_code;
						     	});
						     	if(item.deal_day){
							     	same_data.sort(function(a, b){
					     		    var value1 = a['deal_day'];
									    var value2 = b['deal_day'];
											return value1 < value2 ? 1 : -1;
										});
						     	};
						     	if(same_data.length > 1){
							     	same_data.forEach((tar, num) =>{
							     		str += `<tr>`;
							     		if(num == 0){
							          is_intable_params.forEach((element, index) => {
							            let value = tar[element.name];
							        		if (element.operator) {
							              value = Opreators[element.operator]([tar], element.name)
							           	};
							            if(element.is_merge){
								            str += `<td rowspan="${same_data.length}">${value}</td>`;
							            } else {
								            str += `<td>${value}</td>`;
							            }
							          });
							     		} else {
							          is_intable_params.forEach((element, index) => {
							            let value = tar[element.name];
							        		if (element.operator) {
							              value = Opreators[element.operator]([tar], element.name)
							           	};
							            if(!element.is_merge){
							            	str += `<td>${value}</td>`;
							            }
							          });
							     		}
					          	str += `</tr>`;
							     	})
						     	} else {
					          str += `<tr>`;
					          is_intable_params.forEach(element => {
					            let value = item[element.name];
					            if (element.operator) {
					              value = Opreators[element.operator]([item], element.name)
					            }
					            str += `<td>${value}</td>`;
					          });
					          str += `</tr>`;
						     	}
			        	}
			        })
		        } else {
			        dataItem.forEach(item => {
			          str += `<tr>`;
			          is_intable_params.forEach(element => {
			            let value = item[element.name];
			            if (element.operator) {
			              value = Opreators[element.operator]([item], element.name)
			            }
			            str += `<td>${value}</td>`;
			          });
			          str += `</tr>`;
			        })
		        };
		        str += `</tbody></table></div>`;
		      };
		      if (dataItem instanceof Array && dataItem.length == 0) {
		        str = `<div></div>`;
		      }
    		})
    	}
    }
    if(isReturn){
    	return str
    } else {
    	this.gridContent = str;
    }
  }
  getContent() {
    var that = this;
    return new Promise(function (resolve, reject) {
      that.init().then(function () {
        that.getParameters().then(function () {
          // promise重试
          function retry(fn, times){
              return new Promise((resolve, reject)=>{
                  function run(){
                      fn().then(resolve).catch(err=>{
                          if(times--){
                            console.log(`还有 ${times} 次尝试`)
                            setTimeout(run,60000);
                          }else{
                            reject(err)
                          }
                      })
                  }
                  run()
              })
          };
          retry(that.fetchData.bind(that),20).then(function(){
            console.log("retry 成功")
            resolve()
          }).catch(function(err){
            console.log("retry 失败")
            that.data = null;
            reject(err);
          });
        }).catch(function (err) {
          console.log('getParameters获取数据error',err);
          that.data = null;
          reject(err);
        })
      }).catch(function (err) {
        console.log('原子init error',err);
        that.data = null;
        reject(err);
      })
    })
  }
}

module.exports = Atom;